
// #include "block_queue.hpp"
// #include "tesk.hpp"

// // template<class T>
// // struct pthreaddata
// // {
// //     pthreaddata(std::string name, BlockQueue<T>* bq) : _name(name), _pbq(bq)
// //     {
// //     }
// //     pthread_t _tid;
// //     std::string _name;
// //     BlockQueue<T> *_pbq;
// // };

// // pthread_mutex_t mutex; // 阻塞队列的互斥量

// // pthread_cond_t pcond; // 生产者条件变量
// // pthread_cond_t ccond; // 消费者条件变量

// // BlockQueue<int> bq(&mutex, &pcond, &ccond);//创建一个阻塞队列

// // void *producers_start(void *argc)
// // {
// //     BlockQueue<int> *bq = static_cast<BlockQueue<int> *>(argc);
// //     while (true)
// //     {
// //         sleep(1);
// //         int val = rand() % 10 + 1;
// //         bq->Push(val);
// //         std::cout << "producers->val: " << val << std::endl;
// //     }
// //     return nullptr;
// // }

// // void *consumer_start(void *argc)
// // {
// //     BlockQueue<int> *bq = static_cast<BlockQueue<int> *>(argc);
// //     while (true)
// //     {
// //         int val;
// //         bq->Pop(&val);
// //         std::cout << "consumer->val: " << val << std::endl;
// //     }
// //     return nullptr;
// // }

// // int main()
// // {
// //     // 种下随机数种子
// //     srand((unsigned int)time(nullptr) & 1223423);

// //     pthread_t ptid1,ptid2, ptid3,ptid4;
// //     pthread_t ctid1,ctid2,ctid3,ctid4;

// //     BlockQueue<int> bq(&mutex, &pcond, &ccond);

// //     // 生产者线程
// //     pthread_create(&ptid1, nullptr, producers_start, &bq);
// //     pthread_create(&ptid2, nullptr, producers_start, &bq);
// //     pthread_create(&ptid3, nullptr, producers_start, &bq);
// //     pthread_create(&ptid4, nullptr, producers_start, &bq);

// //     // 消费者线程
// //     pthread_create(&ctid1, nullptr, consumer_start, &bq);
// //     pthread_create(&ctid2, nullptr, consumer_start, &bq);
// //     pthread_create(&ctid3, nullptr, consumer_start, &bq);
// //     pthread_create(&ctid4, nullptr, consumer_start, &bq);

// //     // 等待线程/或者分离线程
// //     pthread_join(ptid1, nullptr);
// //     pthread_join(ptid2, nullptr);
// //     pthread_join(ptid3, nullptr);
// //     pthread_join(ptid4, nullptr);
// //     pthread_join(ctid1, nullptr);
// //     pthread_join(ctid2, nullptr);
// //     pthread_join(ctid3, nullptr);
// //     pthread_join(ctid4, nullptr);

// //     return 0;
// // }

// // void *producers_start(void *argc)
// // {
// //     pthreaddata<int> *data = static_cast<pthreaddata<int> *>(argc);
// //     while (true)
// //     {
// //         //sleep(1);
// //         int val = rand() % 10 + 1;
// //         data->_pbq->Push(val);
// //         std::cout << data->_name << "   producers->val: " << val << std::endl;
// //     }
// //     return nullptr;
// // }

// // void *consumer_start(void *argc)
// // {
// //     pthreaddata<int> *data = static_cast<pthreaddata<int> *>(argc);
// //     while (true)
// //     {
// //         sleep(1);
// //         int val;
// //         data->_pbq->Pop(&val);
// //         std::cout << data->_name << "    consumer->val: " << val << std::endl;
// //     }
// //     return nullptr;
// // }

// // int main()
// // {

// //     std::vector<pthreaddata<int> *> pvect;
// //     std::vector<pthreaddata<int> *> cvect;

// //     for (int i = 0; i < 3; i++)
// //     {
// //         std::string name = "producers pthrea->";
// //         name += std::to_string(i + 1);
// //         pthreaddata<int> *tmp = new pthreaddata<int>(name, &bq);
// //         pthread_create(&(tmp->_tid), nullptr, producers_start, tmp);
// //         pvect.push_back(tmp);
// //     }

// //     for (int i = 0; i < 4; i++)
// //     {
// //         std::string name = "consumer  pthrea->";
// //         name += std::to_string(i + 1);
// //         pthreaddata<int> *tmp = new pthreaddata<int>(name, &bq);
// //         pthread_create(&(tmp->_tid), nullptr, consumer_start, tmp);
// //         cvect.push_back(tmp);
// //     }

// //     for (int i = 0; i < 3; i++)
// //     {
// //         pthread_join((pvect[i]->_tid), nullptr);
// //     }

// //     for (int i = 0; i < 4; i++)
// //     {
// //         pthread_join((cvect[i]->_tid), nullptr);
// //     }

// //     while(1);

// //     return 0;
// // }

// // void *consumer(void *argc)
// // {
// //     while (true)
// //     {
// //         sleep(1);
// //         BlockQueue<int> *bq = static_cast<BlockQueue<int> *>(argc);
// //         int val;
// //         bq->pop(&val);
// //         std::cout << "消费数据: " << val << std::endl;
// //     }

// //     return nullptr;
// // }
// // void *producers(void *argc)
// // {
// //     while (true)
// //     {
// //         //sleep(1);
// //         BlockQueue<int> *bq = static_cast<BlockQueue<int> *>(argc);
// //         int val = rand() % 9 + 1;
// //         bq->push(val);
// //         std::cout << "生产数据: " << val << std::endl;

// //     }

// //     return nullptr;
// // }

// // int main()
// // {
// //     srand((unsigned int)time(nullptr) & 324232);
// //     // 创建阻塞队列
// //     BlockQueue<int> *bq = new BlockQueue<int>(10);

// //     pthread_t c, p;

// //     pthread_create(&p, nullptr, producers, bq);
// //     pthread_create(&c, nullptr, consumer, bq);

// //     pthread_join(c, nullptr);
// //     pthread_join(p, nullptr);
// //     delete bq;

// //     return 0;
// // }

// int myadd(int x, int y)
// {
//     return x + y;
// }

// int opfun(int x, int y, char op)
// {
//     int ret = 0;
//     switch (op)
//     {
//     case '+':
//         ret = x + y;
//         break;
//     case '-':
//         ret = x - y;
//         break;
//     case '*':
//         ret = x * y;
//         break;
//     case '/':
//         if (y == 0)
//         {
//             std::cout << "error" << std::endl;
//             return -1;
//         }
//         ret = x / y;
//         break;
//     case '%':
//         if (y == 0)
//         {
//             std::cout << "error" << std::endl;
//             return -1;
//         }
//         ret = x % y;
//         break;
//     default:
//         std::cout << "error" << std::endl;
//         break;
//     }
//     return ret;
// }

// void *consumer(void *argc)
// {
//     while (true)
//     {
//         //sleep(1);
//         BlockQueue<Tesk> *bq = static_cast<BlockQueue<Tesk> *>(argc);

//         Tesk t;
//         bq->pop(&t);
//         std::cout << "消费任务: " << t._x << " " << t._op << " " << t._y << " = " << t() << std::endl;
//     }

//     return nullptr;
// }
// void *producers(void *argc)
// {
//     while (true)
//     {
//         sleep(1);
//         BlockQueue<Tesk> *bq = static_cast<BlockQueue<Tesk> *>(argc);
//         int x = rand() % 9 + 1;
//         int y = rand() % 9 ;
//         char ops[5] = {'+', '-', '*', '/', '%'};
//         // Tesk t(x,y, myadd);
//         Tesk t(x, y, ops[rand() % 5], opfun);

//         bq->push(t);
//         std::cout << "生产任务: " << x << " " << t._op << " " << y << " = ?" << std::endl;
//     }

//     return nullptr;
// }

// int main()
// {
//     srand((unsigned int)time(nullptr) & 324232);
//     // 创建阻塞队列
//     BlockQueue<Tesk> *bq = new BlockQueue<Tesk>(10);

//     pthread_t c, p;

//     pthread_create(&p, nullptr, producers, bq);
//     pthread_create(&c, nullptr, consumer, bq);

//     pthread_join(c, nullptr);
//     pthread_join(p, nullptr);
//     delete bq;

//     return 0;

// }

#include <iostream>
#include <queue>
#include <stdlib.h>
#include <pthread.h>
#define NUM 8
class BlockQueue
{
private:
    std::queue<int> q;
    int cap;
    pthread_mutex_t lock;
    pthread_cond_t full;
    pthread_cond_t empty;

private:
    void LockQueue()
    {
        pthread_mutex_lock(&lock);
    }
    void UnLockQueue()
    {
        pthread_mutex_unlock(&lock);
    }
    
    void ProductWait()
    {
        pthread_cond_wait(&full, &lock);
    }
    void ConsumeWait()
    {
        pthread_cond_wait(&empty, &lock);
    }
    void NotifyProduct()
    {
        pthread_cond_signal(&full);
    }
    void NotifyConsume()
    {
        pthread_cond_signal(&empty);
    }
    bool IsEmpty()
    {
        return (q.size() == 0 ? true : false);
    }
    bool IsFull()
    {
        return (q.size() == cap ? true : false);
    }

public:
    BlockQueue(int _cap = NUM) : cap(_cap)
    {
        pthread_mutex_init(&lock, NULL);
        pthread_cond_init(&full, NULL);
        pthread_cond_init(&empty, NULL);
    }
    void PushData(const int &data)
    {
        LockQueue();
        while (IsFull())
        {
            NotifyConsume();
            std::cout << "queue full, notify consume data, product stop." << std::endl;

            ProductWait();
        }
        q.push(data);
        // NotifyConsume();
        UnLockQueue();
    }
    void PopData(int &data)
    {
        LockQueue();
        while (IsEmpty())
        {
            NotifyProduct();
            std::cout << "queue empty, notify product data, consume stop." << std::endl;
            ConsumeWait();
        }
        data = q.front();
        q.pop();
        // NotifyProduct();
        UnLockQueue();
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&full);
        pthread_cond_destroy(&empty);
    }
};
void *consumer(void *arg)
{
    BlockQueue *bqp = (BlockQueue *)arg;
    int data;
    for (;;)
    {
        bqp->PopData(data);
        std::cout << "Consume data done : " << data << std::endl;
    }
}
// more faster
void *producter(void *arg)
{
    BlockQueue *bqp = (BlockQueue *)arg;
    srand((unsigned long)time(NULL));
    for (;;)
    {
        int data = rand() % 1024;
        bqp->PushData(data);
        std::cout << "Prodoct data done: " << data << std::endl;
        // sleep(1);
    }
}

int main()
{
    BlockQueue bq;
    pthread_t c, p;
    pthread_create(&c, NULL, consumer, (void *)&bq);
    pthread_create(&p, NULL, producter, (void *)&bq);
    pthread_join(c, NULL);
    pthread_join(p, NULL);
    return 0;
}